Docker Containerization with CI/CD Pipeline#3
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds comprehensive Docker containerization with CI/CD pipeline support to the Reddit modlog bot project, enabling production deployment with automated builds and deployment workflows.
- Adds Docker containerization with multi-stage builds, health checks, and security-focused non-root user configuration
- Implements GitHub Actions CI/CD pipeline for automated multi-platform builds to GitHub Container Registry and Docker Hub
- Introduces pre-commit hooks for code quality validation including security scanning and formatting checks
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| docker-compose.yml | Production-ready Docker Compose configuration with environment variables, health checks, and resource limits |
| Dockerfile | Multi-stage Docker build with Python 3.11-slim, non-root user security, and health check implementation |
| CLAUDE.md | Updated documentation with Docker deployment instructions and CI/CD workflow details |
| .pre-commit-config.yaml | Pre-commit hooks configuration for code quality, security scanning, and Reddit config validation |
| .github/workflows/docker-build.yml | GitHub Actions workflow for automated Docker builds with multi-platform support and dual registry deployment |
| .dockerignore | Docker build context exclusions for sensitive files, logs, and development artifacts |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
docker-compose.yml
Outdated
|
|
||
| # Health check | ||
| healthcheck: | ||
| test: ["CMD", "python", "-c", "import sqlite3; conn = sqlite3.connect('/app/data/modlog.db'); conn.close()"] |
There was a problem hiding this comment.
The health check hardcodes the database path instead of using the DB_PATH environment variable defined in the Dockerfile. This creates inconsistency between the two files and makes the configuration less maintainable.
| test: ["CMD", "python", "-c", "import sqlite3; conn = sqlite3.connect('/app/data/modlog.db'); conn.close()"] | |
| test: ["CMD-SHELL", "python -c \"import os, sqlite3; conn = sqlite3.connect(os.environ['DB_PATH']); conn.close()\""] |
Dockerfile
Outdated
|
|
||
| # Health check | ||
| HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ | ||
| CMD python -c "import sqlite3; conn = sqlite3.connect('${DB_PATH}'); conn.close()" || exit 1 |
There was a problem hiding this comment.
The HEALTHCHECK command uses shell variable expansion (${DB_PATH}) but runs in exec form, which doesn't perform shell expansion. This will cause the health check to fail as it will literally look for a file named '${DB_PATH}' instead of the actual path.
| CMD python -c "import sqlite3; conn = sqlite3.connect('${DB_PATH}'); conn.close()" || exit 1 | |
| CMD python -c "import sqlite3; conn = sqlite3.connect(\"${DB_PATH}\"); conn.close()" || exit 1 |
| hooks: | ||
| - id: reddit-config-check | ||
| name: Check Reddit config safety | ||
| entry: python -c "import json; config = json.load(open('config.json')) if __import__('os').path.exists('config.json') else {}; exit(1) if not config.get('anonymize_moderators', True) else exit(0)" |
There was a problem hiding this comment.
The Reddit config check is implemented as a complex one-liner that's difficult to read and maintain. Consider extracting this to a separate script file for better readability and testability.
.github/workflows/docker-build.yml
Outdated
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Login to GitHub Container Registry | ||
| if: github.event_name != 'pull_request' && (github.ref_type == 'tag' || inputs.deploy_to_main == true) |
There was a problem hiding this comment.
The workflow allows manual deployment to production registries without proper authorization checks. Consider adding an environment protection rule or additional approval step for production deployments to prevent unauthorized releases.
| if: github.event_name != 'pull_request' && (github.ref_type == 'tag' || inputs.deploy_to_main == true) | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME }} | |
| ${{ env.REGISTRY_DOCKERHUB }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build (no push) | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: false | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| deploy-production: | |
| if: github.event_name != 'pull_request' && (github.ref_type == 'tag' || inputs.deploy_to_main == true) | |
| runs-on: ubuntu-latest | |
| environment: production | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GitHub Container Registry |
6b6b411 to
a5ee2fd
Compare
22ece8c to
5b32ecc
Compare
Features: - Complete Docker containerization with s6-overlay init - PUID/PGID support for proper file permissions - Multi-architecture builds (amd64/arm64) - GitHub Actions CI/CD pipeline for ghcr.io publishing - OpenContainer labels for proper metadata Systemd improvements: - Template-based service for multiple subreddits - Per-subreddit config files in /etc/redditmodlog/ - Centralized logging to /var/log/redditmodlog/ - Automatic log rotation (30 days, 100MB max) - Security hardening with read-only filesystem - Resource limits (256MB RAM, 25% CPU) Infrastructure: - Installation script for easy deployment - Logrotate configuration included - Enhanced .gitignore for sensitive files - Updated README with Docker and systemd documentation This provides production-ready deployment options for both Docker and systemd environments.
- Change data directory from /app to /config for consistency - Add startup validation for critical environment variables - Fix GitHub Actions workflow image name to lowercase (GHCR requirement) - Fix health check to use DATABASE_PATH env var - Update all volume mounts to use /config instead of /app - Add proper exit on missing required env vars: - REDDIT_CLIENT_ID - REDDIT_CLIENT_SECRET - REDDIT_USERNAME - REDDIT_PASSWORD - SOURCE_SUBREDDIT - Simplify GitHub Actions tag pattern (remove invalid branch prefix) - Update README documentation for /config paths
Critical fixes from expert review: - Fix multi-arch builds: s6-overlay now selects correct architecture (x86_64 for amd64, aarch64 for arm64, arm for arm/v7) - Fix GitHub Actions SBOM generation image reference - Fix GitHub Actions Trivy security scan image reference - Fix resource limits: use Compose v2 syntax instead of swarm-only deploy - Remove obsolete version directive from docker-compose.yml - Remove unnecessary reverse proxy network comments - Document unsupported env vars (MAX_WIKI_ENTRIES_PER_PAGE, MAX_CONTINUOUS_ERRORS) This resolves blocking issues for arm64 builds and CI/CD pipeline.
9359a70 to
5f43b1b
Compare
Restore .pre-commit-config.yaml that was in original PR but missing from current branch. This file provides code quality, security scanning, and formatting validation hooks.
Add .editorconfig to maintain consistent formatting across editors: - Python: 4 spaces, max line 88 (matches black) - YAML/JSON: 2 spaces - Unix line endings (LF) - UTF-8 encoding - Trim trailing whitespace
- Black reformatted with --line-length=180 - Fixed trailing whitespace and EOF issues - Fixed Dockerfile FROM casing (AS instead of as)
bc62943 to
5ec4421
Compare
Summary
Docker Features
CI/CD Pipeline
Pre-commit Hooks
Test plan
🤖 Generated with Claude Code